package com.hit.server.biz.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hit.daemon.quartz.constants.HitQuartzEnum;
import com.hit.daemon.quartz.constants.JobTypeQuartzEnum;
import com.hit.daemon.quartz.controller.SysJobController;
import com.hit.daemon.quartz.entity.SysJob;
import com.hit.daemon.quartz.service.SysJobService;
import com.hit.server.api.entity.CheckStrategyEntity;
import com.hit.server.api.entity.CheckTaskEntity;
import com.hit.server.api.dto.CheckTaskQueryDTO;
import com.hit.server.api.dto.CheckTaskSaveDTO;
import com.hit.server.api.dto.CheckTaskUpdateDTO;
import com.hit.server.api.entity.RobotEntity;
import com.hit.server.api.type.ScheduleStatusEnums;
import com.hit.server.api.vo.CheckTaskVO;
import com.hit.server.biz.mapper.CheckStrategyMapper;
import com.hit.server.biz.mapper.CheckTaskMapper;
import com.hit.server.api.service.CheckTaskService;
import com.hit.server.biz.mapper.RobotMapper;
import lombok.extern.slf4j.Slf4j;
import org.quartz.SchedulerException;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import lombok.RequiredArgsConstructor;

import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 检测任务
 *
 * @author kehanjiang
 * @date 2025-04-18 09:57:23
 */
@Slf4j
@Service("CheckTaskServiceImpl")
@RequiredArgsConstructor
public class CheckTaskServiceImpl extends ServiceImpl<CheckTaskMapper, CheckTaskEntity> implements CheckTaskService {
    private final CheckStrategyMapper checkStrategyMapper;
    private final RobotMapper robotMapper;

    private final SysJobController sysJobController;
    private final SysJobService sysJobService;

    private CheckTaskVO convertToVO(Object o) {
        if (o instanceof CheckTaskEntity) {
            CheckTaskVO vo = new CheckTaskVO();
            BeanUtil.copyProperties(o, vo);
            //设置其他参数
            Optional.ofNullable(vo.getStrategyId()).ifPresent(strategyId -> {
                CheckStrategyEntity strategy = checkStrategyMapper.selectById(strategyId);
                if (strategy != null) {
                    vo.setStrategyName(strategy.getName());
                    RobotEntity robot = robotMapper.selectById(strategy.getRobotId());
                    if (robot != null) {
                        vo.setRobotName(robot.getName());
                    }
                }
            });
            SysJob sysJob = sysJobService.getById(vo.getJobId());
            vo.setStartTime(sysJob.getStartTime());
            vo.setPreviousTime(sysJob.getPreviousTime());
            vo.setNextTime(sysJob.getNextTime());
            return vo;
        }
        return null;
    }

    private void preCheck(CheckTaskEntity entity, Boolean update) {
        Long id = entity.getId();
        String name = entity.getName();
        if (update) {//更新操作
            Assert.notNull(id, "id不可为空！");
        } else {
            Assert.hasText(name, "name不可为空！");
        }
    }

    @Override
    public Page<CheckTaskVO> getCheckTaskPage(Page page, CheckTaskQueryDTO dto) {
        CheckTaskEntity entity = new CheckTaskEntity();
        BeanUtils.copyProperties(dto, entity);
        entity.setName(null);
        final String name = dto.getName();
        LambdaQueryWrapper<CheckTaskEntity> wrapper = new LambdaQueryWrapper<>(entity);
        wrapper.like(StringUtils.hasText(name), CheckTaskEntity::getName, name);
        wrapper.orderByAsc(CheckTaskEntity::getId);
        return (Page<CheckTaskVO>) this.page(page, wrapper)
                .convert(this::convertToVO);
    }

    @Override
    public CheckTaskVO getCheckTaskById(Long id) {
        Assert.notNull(id, "id不可为空！");
        return convertToVO(this.getById(id));
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean saveCheckTask(CheckTaskSaveDTO dto) {
        CheckTaskEntity entity = new CheckTaskEntity();
        BeanUtils.copyProperties(dto, entity);
        this.preCheck(entity, false);
        this.save(entity);

        //生成quartz定时任务
        Long sysJobId = sysJobController.save(SysJob.builder()
                .jobName(entity.getName())
                .jobGroup("DEFAULT_GROUP")
                .jobType(JobTypeQuartzEnum.SPRING_BEAN.getType())
                .className("CheckTaskServiceImpl")
                .methodName("executeTask")
                .methodParamsValue(String.valueOf(entity.getId()))
                .cronExpression(entity.getScheduleCron())
                .jobStatus(HitQuartzEnum.JOB_STATUS_NOT_RUNNING.getType())
                .jobOrder("1")
                .jobTenantType("1")
                .misfirePolicy("3")//错失执行策略（1错失周期立即执行 2错失周期执行一次 3下周期执行）
                .build()).getData();
        if (ScheduleStatusEnums.ON.getCode().equals(entity.getScheduleStatus())) {//开启定时任务
            try {
                sysJobController.startJob(sysJobId);
            } catch (SchedulerException e) {
                throw new RuntimeException(e);
            }
        }
        //写入jobId
        entity.setJobId(sysJobId);
        this.updateById(entity);
        return Boolean.TRUE;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateCheckTaskById(CheckTaskUpdateDTO dto) {
        CheckTaskEntity entity = new CheckTaskEntity();
        BeanUtils.copyProperties(dto, entity);
        this.preCheck(entity, true);

        Long jobId = entity.getJobId();
        String cron = entity.getScheduleCron();
        String name = entity.getName();
        SysJob sysJob = this.sysJobService.getById(jobId);
        if (!sysJob.getCronExpression().equals(cron) || !sysJob.getJobName().equals(name)) {
            if (HitQuartzEnum.JOB_STATUS_RUNNING.getType().equals(sysJob.getJobStatus())) {
                throw new RuntimeException("修改任务名称或cron定时表达式需要先关闭定时任务状态！");
            }
            sysJob.setCronExpression(cron);
            sysJob.setJobName(name);
            sysJobController.updateById(sysJob);
        }

        if (ScheduleStatusEnums.ON.getCode().equals(entity.getScheduleStatus()) &&
                (HitQuartzEnum.JOB_STATUS_RELEASE.getType().equals(sysJob.getJobStatus())
                        || HitQuartzEnum.JOB_STATUS_NOT_RUNNING.getType().equals(sysJob.getJobStatus()))
        ) {//开启定时任务
            try {
                sysJobController.startJob(jobId);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        } else if (ScheduleStatusEnums.OFF.getCode().equals(entity.getScheduleStatus()) &&
                HitQuartzEnum.JOB_STATUS_RUNNING.getType().equals(sysJob.getJobStatus())
        ) {//关闭定时任务
            sysJobController.shutdownJob(jobId);
        }

        return this.updateById(entity);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean removeCheckTaskBatchByIds(List<Long> ids) {
        Assert.notEmpty(ids, "ID不可为空！");
        List<CheckTaskEntity> taskList = this.listByIds(ids);
        List<Long> sysJobIds = taskList.stream().map(CheckTaskEntity::getJobId).collect(Collectors.toList());
        List<SysJob> sysJobs = sysJobService.listByIds(sysJobIds);
        for (SysJob sysJob : sysJobs) {
            Long sysJobId = sysJob.getJobId();
            if (HitQuartzEnum.JOB_STATUS_RUNNING.getType().equals(sysJob.getJobStatus())) {
                throw new RuntimeException("运行中的任务无法删除，请确保任务已关闭！");
//                sysJobController.shutdownJob(sysJobId);
            }
            sysJobController.removeById(sysJobId);
        }
        return this.removeBatchByIds(ids);
    }

    @Override
    public Boolean runOnceById(Long id) {
        Assert.notNull(id, "ID不可为空！");
        CheckTaskEntity taskEntity = this.getById(id);
        SysJob sysJob = sysJobService.getById(taskEntity.getJobId());
        if (HitQuartzEnum.JOB_STATUS_RUNNING.getType().equals(sysJob.getJobStatus())) {
            throw new RuntimeException("立刻执行一次任务需要先关闭定时任务状态！");
        }
        try {
            sysJobController.runJob(sysJob.getJobId());
        } catch (SchedulerException e) {
            throw new RuntimeException(e);
        }
        return Boolean.TRUE;
    }


    /**
     * 任务执行入口
     *
     * @param taskId
     * @return
     */
    public boolean executeTask(String taskId) {
        try {
            //TODO 任务执行入口
            CheckTaskEntity task = this.getById(taskId);
            Assert.notNull(task, "任务不存在！");
            CheckStrategyEntity strategy = checkStrategyMapper.selectById(task.getStrategyId());
            Assert.notNull(strategy, "策略不存在！");
            RobotEntity robot = robotMapper.selectById(strategy.getRobotId());
            Assert.notNull(robot, "机器人不存在！");
            log.info("====> {}", task.getName());
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        } finally {

        }
        return Boolean.TRUE;
    }
}